/**
* A synchronous TCP daytime client
*/

#include <array>
#include <filesystem>
#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: " <<std::filesystem::path(argv[0]).filename() << " <host>" << std::endl;
            return 1;
        }

        // executor
        boost::asio::io_context io_context;
        // 我们需要将指定为应用程序参数的服务器名称转换为 TCP 端点。为此，我们使用 ip::tcp::resolver 对象
        /*
        将查询向前解析为一个条目列表。
        该函数用于将主机名和服务名解析为端点条目列表。
        在 POSIX 系统中，服务名称通常定义在 /etc/services 文件中。
        在 Windows 系统中，服务名称可以在 c:\windows\system32\drivers\etc\services 文件中找到。操作系统在解析服务名称时可能会使用其他位置。
        */

        /*  C:/Windows/System32/drivers/etc/services
        echo                7/tcp
        echo                7/udp
        discard             9/tcp    sink null
        discard             9/udp    sink null
        systat             11/tcp    users                  #Active users
        systat             11/udp    users                  #Active users
        daytime            13/tcp
        daytime            13/udp
        qotd               17/tcp    quote                  #Quote of the day
        qotd               17/udp    quote                  #Quote of the day
        chargen            19/tcp    ttytst source          #Character generator
        chargen            19/udp    ttytst source          #Character generator
        ftp-data           20/tcp                           #FTP, data
        ftp                21/tcp                           #FTP. control
        ssh                22/tcp                           #SSH Remote Login Protocol
        telnet             23/tcp
        smtp               25/tcp    mail                   #Simple Mail Transfer Protocol
        time               37/tcp    timserver
        time               37/udp    timserver
        rlp                39/udp    resource               #Resource Location Protocol
        nameserver         42/tcp    name                   #Host Name Server
        nameserver         42/udp    name                   #Host Name Server
        */
        tcp::resolver resolver(io_context);
        // 我感觉resolver是一个查询服务的端口的一个包装器, 传入daytime, 他查表.
        // 得到端口13/tcp 13/udp, 如果传入的是https, 可能就是443/tcp 443/udp
        tcp::resolver::results_type endpoints = resolver.resolve(argv[1], "daytime");
        // 最终得到是端点的列表. 你可以使用迭代器遍历他们.
        for (auto endpoint_iterator = endpoints.begin(); endpoint_iterator != endpoints.end(); ++endpoint_iterator)
        {
            // std::cout << endpoint_iterator->endpoint() << std::endl;
        }
        std::cout << std::endl;

        // create socket
        tcp::socket socket(io_context);
        // connect it!
        // 上面获取的端点列表可能同时包含 IPv4 和 IPv6 端点，因此我们需要尝试每个端点，直到找到一个有效的。这使客户端程序独立于特定的 IP 版本。
        boost::asio::connect(socket, endpoints);

        for (;;)
        {
            std::array<char, 128> buf{};
            boost::system::error_code error;

            // boost::asio::buffer() 函数会自动确定数组的大小，以帮助防止缓冲区溢出。
            size_t len = socket.read_some(boost::asio::buffer(buf), error);

            if (error == boost::asio::error::eof)
                break; // Connection closed cleanly by peer.
            else if (error)
                throw boost::system::system_error(error); // Some other error.

            std::cout.write(buf.data(), len).flush();
        }
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}
